package com.wangdao.wechatmall.service.wx;

import com.wangdao.wechatmall.bean.bo.wx.*;
import com.wangdao.wechatmall.bean.pojo.*;
import com.wangdao.wechatmall.bean.vo.wx.*;
import com.wangdao.wechatmall.exception.CouponUnusbaleException;
import com.wangdao.wechatmall.mapper.*;
import com.wangdao.wechatmall.util.BooleanTransformUtils;
import com.wangdao.wechatmall.util.DateTransformUtil;
import lombok.SneakyThrows;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.System;
import java.math.BigDecimal;
import java.util.*;

/**
 * @ClassName: WXCartServiceImpl
 * @Description ${DESCRIPTION}
 * @Author Xinhao Yi
 * @Date 2021/7/11  21:18
 */
@Service
public class WXCartServiceImpl implements WXCartService {

    @Autowired
    CartMapper cartMapper;

    @Autowired
    GoodsProductMapper goodsProductMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    GrouponMapper grouponMapper;

    @Autowired
    GrouponRulesMapper grouponRulesMapper;

    @Autowired
    AddressMapper addressMapper;

    @Autowired
    CouponUserMapper couponUserMapper;

    @Autowired
    CouponMapper couponMapper;

    private static final long ONE_DAY_MILLISECOND = 86400000;//一天的毫秒数

    private static final Integer MIN_NO_FREIGHT_CHECKED_GOODS_AMOUNT = 100;//免运费所要求的购物车内选中的最小总金额为100元

    @Override
    public WXCartIndexVO list(Boolean onlyChecked) {
        //去查购物车数据库
        CartExample cartExample = new CartExample();
        CartExample.Criteria criteria = cartExample.createCriteria();
        //只查找没被删掉的
        criteria.andDeletedEqualTo(false);
        //看onlyChecked的值，如果onlyChecked为true，那么仅查找选中的
        if (onlyChecked) {
            criteria.andCheckedEqualTo(true);
        }
        List<Cart> cartList = cartMapper.selectByExample(cartExample);

        //购物车内所有的商品数目
        Integer goodsCount = 0;
        //购物车内被选中的商品数目
        Integer checkedGoodsCount = 0;
        //总金额
        BigDecimal goodsAmount = new BigDecimal("0.00");
        //选中的总金额
        BigDecimal checkedGoodsAmount = new BigDecimal("0.00");

        for (Cart cart : cartList) {
            Integer goodsNum = Integer.valueOf(cart.getNumber());
            goodsCount += goodsNum;
            BigDecimal price = cart.getPrice();
            goodsAmount = goodsAmount.add(price);
            //检查一下这个是不是被选中的 1即true表示被选中
            if (cart.getChecked()) {
                checkedGoodsCount += goodsNum;
                checkedGoodsAmount = checkedGoodsAmount.add(price);
            }

        }
        WXCartTotalBeanVO cartTotal = new WXCartTotalBeanVO();
        cartTotal.setGoodsCount(goodsCount);
        cartTotal.setCheckedGoodsCount(checkedGoodsCount);
        cartTotal.setGoodsAmount(goodsAmount);
        cartTotal.setCheckedGoodsAmount(checkedGoodsAmount);

        WXCartIndexVO wxCartIndexVO = new WXCartIndexVO();
        wxCartIndexVO.setCartList(cartList);
        wxCartIndexVO.setCartTotal(cartTotal);
        return wxCartIndexVO;
    }


    public WXCartIndexVO list(Integer cartId, Boolean onlyChecked) {
        //去查购物车数据库
        CartExample cartExample = new CartExample();
        CartExample.Criteria criteria = cartExample.createCriteria();
        //只查找没被删掉的
        criteria.andDeletedEqualTo(false);
        //只查cartId的那一项，也就是快速增加 firstAdd
        if (cartId != null && cartId > 0) {
            criteria.andIdEqualTo(cartId);
        }
        //看onlyChecked的值，如果onlyChecked为true，那么仅查找选中的
        if (onlyChecked) {
            criteria.andCheckedEqualTo(true);
        }
        List<Cart> cartList = cartMapper.selectByExample(cartExample);

        //购物车内所有的商品数目
        Integer goodsCount = 0;
        //购物车内被选中的商品数目
        Integer checkedGoodsCount = 0;
        //总金额
        BigDecimal goodsAmount = new BigDecimal("0.00");
        //选中的总金额
        BigDecimal checkedGoodsAmount = new BigDecimal("0.00");

        for (Cart cart : cartList) {
            Integer goodsNum = Integer.valueOf(cart.getNumber());
            goodsCount += goodsNum;
            BigDecimal price = cart.getPrice();
            goodsAmount = goodsAmount.add(price);
            //检查一下这个是不是被选中的 1即true表示被选中
            if (cart.getChecked()) {
                checkedGoodsCount += goodsNum;
                checkedGoodsAmount = checkedGoodsAmount.add(price);
            }

        }
        WXCartTotalBeanVO cartTotal = new WXCartTotalBeanVO();
        cartTotal.setGoodsCount(goodsCount);
        cartTotal.setCheckedGoodsCount(checkedGoodsCount);
        cartTotal.setGoodsAmount(goodsAmount);
        cartTotal.setCheckedGoodsAmount(checkedGoodsAmount);

        WXCartIndexVO wxCartIndexVO = new WXCartIndexVO();
        wxCartIndexVO.setCartList(cartList);
        wxCartIndexVO.setCartTotal(cartTotal);
        return wxCartIndexVO;
    }

    @Override
    public Boolean checked(WXCartCheckedBO param) {
        List<Integer> productIds = param.getProductIds();
        Boolean isChecked = BooleanTransformUtils.checkedInteger2Boolean(param.getIsChecked());
        try {
            for (Integer productId : productIds) {
                CartExample cartExample = new CartExample();
                CartExample.Criteria criteria = cartExample.createCriteria();
                criteria.andProductIdEqualTo(productId);

                Cart cart = new Cart();
                cart.setChecked(isChecked);
                //更新checked
                int i = cartMapper.updateByExampleSelective(cart, cartExample);
                if (i == 0) {
                    return false;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    //编辑cart
    @Override
    public Integer update(WXCartUpdateBO param) {
        //购物车里该订单的id
        int id = param.getId();
        int goodsId = param.getGoodsId();
        int productId = param.getProductId();
        //更新后的number
        int number = param.getNumber();

        //数据校验
        //先拿到购物车里这一项产品原来有多少个，即原来的number---->originalNumber
        Cart cart = cartMapper.selectByPrimaryKey(id);
        Short originalNumber = cart.getNumber();

        //如果新的number比原来的number要小，那库存肯定够了，只是要修改产品的剩余数量
        if (number < originalNumber) {
            //原库存需要增加的量
            int restAddNum = originalNumber - number;
            //查找goods_products表中的剩余数量
            int totalNumber = goodsProductMapper.selectByPrimaryKey(productId).getNumber();
            //调整goods_products表中的剩余数量
            GoodsProduct goodsProduct = new GoodsProduct();
            goodsProduct.setId(productId);
            goodsProduct.setNumber(totalNumber + restAddNum);
            int i = goodsProductMapper.updateByPrimaryKeySelective(goodsProduct);
            if (i == 0) {
                //更新失败
                return 405;
            }
        }
        //number > originalNumber
        else {
            //原库存需要减少的量
            int restDecreaseNum = number - originalNumber;
            //查找goods_products表中的剩余数量
            int totalNumber = goodsProductMapper.selectByPrimaryKey(productId).getNumber();
            //比较一下restDecreaseNum和totalNumber
            //如果库存不够了，直接404
            if (totalNumber < restDecreaseNum) {
                return 404;
            }
            //调整goods_products表中的剩余数量
            GoodsProduct goodsProduct = new GoodsProduct();
            goodsProduct.setId(productId);
            goodsProduct.setNumber(totalNumber - restDecreaseNum);
            int i = goodsProductMapper.updateByPrimaryKeySelective(goodsProduct);
            if (i == 0) {
                //更新失败
                return 405;
            }
        }

        //到这里数据校验和数量调整就做完了
        //我们开始更新cart表
        Cart updateCart = new Cart();
        updateCart.setId(id);
        updateCart.setGoodsId(goodsId);
        updateCart.setProductId(productId);
        updateCart.setNumber((short) number);
        int i = cartMapper.updateByPrimaryKeySelective(updateCart);

        if (i == 0) {
            return 405;
        } else {
            return 200;
        }
    }

    //这里只给productIds是有原因的，因为我们购物车里add进商品时，如果一前一后买的商品具有相同的productId，他们会合并为一项
    @Override
    public Integer delete(WXCartDeleteBO param) {
        List<Integer> productIds = param.getProductIds();
        for (Integer productId : productIds) {
            //先去调整products中的数量
            //先拿到购物车里这一项产品原来有多少个，即原来的number---->originalNumber，这些数量全部要补回去
            CartExample cartExample = new CartExample();
            CartExample.Criteria criteria = cartExample.createCriteria();
            criteria.andProductIdEqualTo(productId);
            List<Cart> cartList = cartMapper.selectByExample(cartExample);
            Cart cart = cartList.get(0);
            Short restAddNum = cart.getNumber();
            //查找goods_products表中的剩余数量
            int totalNumber = goodsProductMapper.selectByPrimaryKey(productId).getNumber();
            //调整goods_products表中的剩余数量
            GoodsProduct goodsProduct = new GoodsProduct();
            goodsProduct.setId(productId);
            goodsProduct.setNumber(totalNumber + restAddNum);
            int i = goodsProductMapper.updateByPrimaryKeySelective(goodsProduct);
            if (i == 0) {
                //删除失败
                return 404;
            }
            cart.setDeleted(true);
            //再去删除cart表单中的数据
            int i1 = cartMapper.updateByPrimaryKeySelective(cart);
            if (i1 == 0) {
                return 404;
            }
        }
        return 200;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    //要判断是不是fastAdd
    public Integer add(WXCartAddBO param, Boolean isFastAdd) {
        int goodsId = param.getGoodsId();
        int productId = param.getProductId();
        int number = param.getNumber();

        //库存调整
        //先去查product表
        GoodsProduct goodsProductTemp = goodsProductMapper.selectByPrimaryKey(productId);
        //商品库存不足
        if (goodsProductTemp == null || goodsProductTemp.getNumber() < number) {
            return -1;
        }
        //库存够了
        //减库存
        goodsProductTemp.setNumber(goodsProductTemp.getNumber() - number);
        goodsProductMapper.updateByPrimaryKey(goodsProductTemp);

        //todo 我们要想办法去拿到当前是哪个用户在使用，拿到当前的userId
        // 问题解决了！
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipals().getPrimaryPrincipal();
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        List<User> users = userMapper.selectByExample(userExample);
        Integer userId = users.get(0).getId();

        //用goodsId去goods表里面拿 goodsSn，goodsName
        Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
        String goodsSn = goods.getGoodsSn();
        String goodsName = goods.getName();

        //用productsId去products表里面拿specifications当作specifications
        GoodsProduct goodsProduct = goodsProductMapper.selectByPrimaryKey(productId);
        String[] specifications = goodsProduct.getSpecifications();

        //products表里面拿price，并算出总价钱price
        BigDecimal priceSingel = goodsProduct.getPrice();

        BigDecimal price = priceSingel.multiply(new BigDecimal(number));

        //用productId 去products表里面拿url
        String url = goodsProduct.getUrl();

        //拼出我们想要的cart来
        Cart cart = new Cart();
        cart.setUserId(userId);
        cart.setGoodsId(goodsId);
        cart.setGoodsSn(goodsSn);
        cart.setGoodsName(goodsName);
        cart.setProductId(productId);
        cart.setPrice(price);
        cart.setNumber((short) number);
        cart.setSpecifications(specifications);
        cart.setChecked(true);
        cart.setPicUrl(url);

        Date date = DateTransformUtil.dateFormat(new Date(System.currentTimeMillis()));
        cart.setAddTime(date);
        cart.setUpdateTime(date);
        cart.setDeleted(false);


        //到这里要去查一下cart表里面是否有userId,goodsId,productId都与之相等的列(且未被删除)，如果有的话，需要合并数据而不是增加
        //根据用户id，商品id，货品id去查购物车中是否已有该条记录(如果是fastadd则不用)
        if (!isFastAdd) {
            CartExample cartExample = new CartExample();
            CartExample.Criteria cartExampleCriteria = cartExample.createCriteria();
            cartExampleCriteria.andDeletedEqualTo(false)
                    .andUserIdEqualTo(userId)
                    .andGoodsIdEqualTo(goodsId)
                    .andProductIdEqualTo(productId);
            List<Cart> cartList = cartMapper.selectByExample(cartExample);

            //如果真的找到了，有需要合并的，那么就要执行合并操作
            if (cartList != null && cartList.size() > 0) {
                cart = cartList.get(0);
                //更改price值
                cart.setPrice(goodsProduct.getPrice().multiply(new BigDecimal(number)).add(cart.getPrice()));
                //更改number值
                cart.setNumber((short) (number + cart.getNumber()));
                int i = cartMapper.updateByPrimaryKeySelective(cart);
                if (i == 1) {
                    return 0;
                } else {
                    return -2;
                }

            }
        }

        //把cart插入到数据库中
        int i = cartMapper.insertSelective(cart);

        //如果是fastAdd
        //比较特殊，要返回新的cart的id
        if (isFastAdd) {
            return cart.getId();
        }

        //普通的add方法
        if (i == 1) {
            return 0;
        } else {
            return -2;
        }

    }

    /**
     * 查找购物车里商品的总数量
     *
     * @return
     */
    @Override
    public Integer countTotalGoodsNum() {
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipals().getPrimaryPrincipal();
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        List<User> users = userMapper.selectByExample(userExample);
        Integer userId = users.get(0).getId();
        //根据userId去查找去所有的cart，把里面number的数量加起来
        CartExample cartExample = new CartExample();
        CartExample.Criteria cartCriteria = cartExample.createCriteria();
        cartCriteria.andUserIdEqualTo(userId);
        //只查没删掉的
        cartCriteria.andDeletedEqualTo(false);
        List<Cart> cartList = cartMapper.selectByExample(cartExample);

        Integer totalGoodsNum = 0;
        for (Cart cart : cartList) {
            Short number = cart.getNumber();
            totalGoodsNum += number;
        }
        return totalGoodsNum;
    }

    /**
     * 查找购物车里项目的总条数
     *
     * @return
     */
    public Integer countTotalCartsNum() {
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipals().getPrimaryPrincipal();
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        List<User> users = userMapper.selectByExample(userExample);
        Integer userId = users.get(0).getId();
        //根据userId去查找去所有的cart，把里面number的数量加起来
        CartExample cartExample = new CartExample();
        CartExample.Criteria cartCriteria = cartExample.createCriteria();
        cartCriteria.andUserIdEqualTo(userId);
        //只查没删掉的
        cartCriteria.andDeletedEqualTo(false);
        List<Cart> cartList = cartMapper.selectByExample(cartExample);

        Integer totalCartNum = 0;
        for (Cart cart : cartList) {

            totalCartNum++;
        }
        return totalCartNum;
    }

    @Override
    public Integer removeCartByCartId(Integer cardId) {
        Cart cart = new Cart();
        cart.setId(cardId);
        cart.setDeleted(true);
        int affectedRows = cartMapper.updateByPrimaryKeySelective(cart);

        return affectedRows;
    }

    @Override
    public WXCartCheckOutVO getCheckOutVO(WXCartCheckOutBO param, WXCartIndexVO wxCartIndexVO)  {

        //拿到checkedGoodsList
        List<Cart> checkedGoodsList = wxCartIndexVO.getCartList();

        //拿到cartTotal
        WXCartTotalBeanVO cartTotal = wxCartIndexVO.getCartTotal();

        /**
         * 拿当前登录的user
         */
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipals().getPrimaryPrincipal();
        UserExample userExample = new UserExample();
        UserExample.Criteria criteria = userExample.createCriteria();
        criteria.andUsernameEqualTo(username);
        List<User> users = userMapper.selectByExample(userExample);
        User user = users.get(0);

        //用户id
        Integer userId = user.getId();
        //购物车id，如果是普通的购买，那么这里为0
        Integer cartId = param.getCartId();
        //地址id
        Integer addressId = param.getAddressId();
        //优惠劵id
        Integer couponId = param.getCouponId();
        //团购id，团购id<=0表示没有参与团购优惠
        Integer grouponRulesId = param.getGrouponRulesId();

        //创建我们的返回结果
        WXCartCheckOutVO wxCartCheckOutVO = new WXCartCheckOutVO();
        //把checkedGoodsList放进去
        wxCartCheckOutVO.setCheckedGoodsList(checkedGoodsList);
        //首先处理用户地址相关
        //拿到UserAddress内部静态类，创建其对象，并赋值
        //如果地址id为0，返回默认id，如果不是0，则查找对应地址
        //如果根本就没有地址选项，返回null，同时把addressId设置为0
        //queryAddressByUserId是自己实现的辅助方法
        Address checkedAddress = queryAddressByUserId(userId, addressId);
        if (checkedAddress != null) {
            wxCartCheckOutVO.setCheckedAddress(checkedAddress);
            wxCartCheckOutVO.setAddressId(addressId);
        } else {
            wxCartCheckOutVO.setCheckedAddress(null);
            wxCartCheckOutVO.setAddressId(0);
        }


        //处理商品总费用goodsTotalPrice，注意是被选中的
        BigDecimal goodsTotalPrice = cartTotal.getCheckedGoodsAmount();
        //set进去
        wxCartCheckOutVO.setGoodsTotalPrice(goodsTotalPrice);


        //todo 目前处理运费的逻辑
        // 根据总金额是否满100来决定是否有运费，运费为8元

        //拿到购物车中被选中购物车项cart的加起来的总金额
        BigDecimal checkedGoodsAmount = cartTotal.getCheckedGoodsAmount();
        //与100作比较
        int cmp = checkedGoodsAmount.compareTo(new BigDecimal(MIN_NO_FREIGHT_CHECKED_GOODS_AMOUNT));
        if (cmp < 0) {
            //总金额比100小----->有运费
            wxCartCheckOutVO.setFreightPrice(8);
        } else {
            //免运费
            wxCartCheckOutVO.setFreightPrice(0);
        }

        //处理优惠劵
        //优惠券相关,根据用户id查询其所有优惠券，如果用户自己选择了优惠券，那优惠券id就不是0了
        // 判断可用优惠券的数量，
        // 挑选优惠金额最大的优惠券，作为默认使用的优惠券

        Coupon coupon = null;
        //拿到该用户在该订单下(满足类型条件)，所有没有删除，没有使用过，也没有过期的优惠劵list
        //todo 这里有bug，前端传过来的couponId好像默认是10，很奇怪
        // 问题已解决，是因为我的返回的couponId的问题
//        List<Coupon> couponList = queryAvailableCouponList(userId, wxCartIndexVO, couponId);

        //拿到这个用户的所有优惠劵
//        List<Coupon> couponList = queryAvailableCouponListTemp(userId, wxCartIndexVO, couponId);

        List<Coupon> couponList = queryAvailableCouponListOthers(userId, wxCartIndexVO, couponId);//获取可用优惠券订单列表

        if (couponId > 0) {
            //用户自己选了优惠券的情况

            CouponUser couponUser = couponUserMapper.selectByPrimaryKey(couponId);
            //拿到couponUser的couponId
            Integer couponIdTemp = couponUser.getCouponId();
            //再用couponIdTemp去查找coupon
            coupon = couponMapper.selectByPrimaryKey(couponIdTemp);

            //检查一下，我们的couponList里面有没有这一个coupon，因为可能写优惠劵的模块在这里没有维护一个正确的可用List<Coupon> couponList
            //如果没有的话，我们仍然取默认值！！！
            if (!couponList.contains(coupon)) {
                coupon = couponList.get(0);
            }
        }
        //用户没有选择优惠劵，默认为0，就要选择默认优惠劵
        else if (couponId == 0) {
            if (couponList.size() > 0) {
                //可用列表是根据优惠金额从大到小排序的，因此第0个就是优惠值最多的，默认用户会使用这张
                coupon = couponList.get(0);
            }
        }
//        else if (couponId == -1)，即不用优惠劵的情况

        //决定couponId的返回值，来决定前端关于优惠劵那一块，是显示优惠金额还是显示还有多少优惠劵可用，还是显示没有优惠劵可用
        if (couponList.size() > 0 && couponId != -1) {//选择设置是否显示可用优惠券数量
            wxCartCheckOutVO.setCouponId(1);//有可用优惠券,并且要使用,返回couponId为1，才显示优惠金额
        } else if (couponList.size() > 0 && couponId == -1) {
            wxCartCheckOutVO.setCouponId(-1);//有但选择不使用，显示可用优惠劵的数量
        } else {
            wxCartCheckOutVO.setCouponId(0);//没有可用优惠劵默认显示0，提示你没有优惠劵可用
        }


        wxCartCheckOutVO.setAvailableCouponLength(couponList.size());

        if (coupon != null) {
            //set进优惠金额
            wxCartCheckOutVO.setCouponPrice(coupon.getDiscount());
        }//否则就是没有合适的优惠券，用默认值0；也可能是用户选择不适用优惠券，所以还要设置可用setAvailableCouponLength
        else {
            //没有优惠金额
            wxCartCheckOutVO.setCouponPrice(new BigDecimal(0));
        }

        //处理团购折扣
        BigDecimal groupDiscount = queryGroupDiscount(userId, grouponRulesId, wxCartIndexVO);

        //groupDiscount转换为grouponPrice
        int grouponPrice = groupDiscount.intValue();
        //set进去
        wxCartCheckOutVO.setGrouponPrice(grouponPrice);

        //然后我们要开始算各种折扣和运费后的实际总价格
        //加上运费，减去优惠劵优惠金额，减去团购优惠金额
        BigDecimal actualTotalPrice = goodsTotalPrice.add(new BigDecimal(wxCartCheckOutVO.getFreightPrice()))
                .subtract(wxCartCheckOutVO.getCouponPrice())
                .subtract(groupDiscount);

        //set进去
        wxCartCheckOutVO.setActualPrice(actualTotalPrice);
        wxCartCheckOutVO.setOrderTotalPrice(actualTotalPrice);
        //todo
        return wxCartCheckOutVO;
    }

    /**
     * 辅助方法
     * 通过用户id拿到地址，如果有地址id就查对应地址id的，如果地址id为0，也就是默认情况，直接返回第一个地址，也就是默认地址
     * 如果地址表里没有东西，返回null
     *
     * @param userId
     * @param addressId
     * @return
     */

    @SneakyThrows
    public Address queryAddressByUserId(Integer userId, Integer addressId) {

        AddressExample userAddressExample = new AddressExample();
        AddressExample.Criteria addressExampleCriteria = userAddressExample.createCriteria();
        userAddressExample.setOrderByClause("is_default" + " " + "desc");
        addressExampleCriteria.andUserIdEqualTo(userId)
                .andDeletedEqualTo(false);
        if (addressId != 0) {
            addressExampleCriteria.andIdEqualTo(addressId);
        }

        List<Address> userAddressList = addressMapper.selectByExample(userAddressExample);
        if (userAddressList != null && userAddressList.size() > 0) {
            return userAddressList.get(0);
        }
        return null;
    }

    /**
     * 辅助方法：
     * 拿到该用户可用的优惠券
     *
     * @param userId
     * @param cartInfo
     * @param couponId
     * @return
     */
    @Override
    public List<Coupon> queryAvailableCouponList(Integer userId, WXCartIndexVO cartInfo, Integer couponId) {
        //先根据我们查到的静态购物车信息cartInfo拿到cartList
        List<Cart> cartList = cartInfo.getCartList();
        //存放所有可用的优惠劵
        List<Coupon> couponList = new ArrayList<>();

        CouponUserExample couponUserExample = new CouponUserExample();
        CouponUserExample.Criteria criteria = couponUserExample.createCriteria();
        Date nowTime = new Date(System.currentTimeMillis());
        nowTime = DateTransformUtil.dateFormat(nowTime);
        criteria.andDeletedEqualTo(false)  //拿未被删除的优惠券
                .andStatusEqualTo((short) 0)      //拿状态码为0也就是未被使用过的优惠券
                .andUserIdEqualTo(userId)  //拿当前用户拥有的优惠劵
                .andStartTimeLessThanOrEqualTo(nowTime)   //优惠券开始时间要早于或等于当前时间
                .andAddTimeLessThanOrEqualTo(nowTime);      //优惠券添加的时间要早于或等于当前时间couponUserList
        //按照增加时间由大到小排序
        couponUserExample.setOrderByClause("add_time" + " " + "desc");
        //按照上述条件拿到该用户的所有优惠劵 List<CouponUser>
        List<CouponUser> couponUserList = couponUserMapper.selectByExample(couponUserExample);
        //创建一个ArrayList<Integer> couponIds，用来存放拿到的该用户持有的所有优惠券的优惠劵id
        List<Integer> couponIds = new ArrayList<>();

        //说明该用户没有优惠劵
        //如果List<CouponUser> couponUserList为空，直接返回一个空的ArrayList即可
        if (couponUserList.size() == 0) {
            return new ArrayList<Coupon>();
        }

        //该用户有优惠劵
        for (CouponUser couponUser : couponUserList) {
            couponIds.add(couponUser.getCouponId());
        }

        //拿优惠劵的list
        CouponExample couponExample = new CouponExample();
        //根据优惠金额的力度由大到小排列的
        couponExample.setOrderByClause("discount" + " " + "desc");
        couponExample.createCriteria()
                .andMinLessThanOrEqualTo(cartInfo.getCartTotal().getCheckedGoodsAmount())  //我们这个购物车内选中商品的总金额要大于优惠劵使用的最小额度
                .andIdIn(couponIds)  //要在couponIds范围内，也就是该用户拥有的优惠劵的id
                .andDeletedEqualTo(false)  //未被删除的
                .andStatusEqualTo((short) 0);    //未被使用的
        couponList = couponMapper.selectByExample(couponExample);

        if (couponList.size() == 0){
            //说明没有可以用的，返回空
            return new ArrayList<>();
        }

        //维护一张优惠劵的couponId与优惠劵种类coupon的对应map
        Map<Integer, Coupon> couponTypeMap = new HashMap<>();
        for (Coupon coupon : couponList) {
            if (!couponTypeMap.containsKey(coupon.getId())) {
                couponTypeMap.put(coupon.getId(), coupon);
            }
        }

        //遍历我们拿到的所有couponUserList，看每一条合不合格
        for (CouponUser couponUser : couponUserList) {
            //找到该条couponUser对应的优惠劵种类couponType
            Coupon couponType = null;
            for (Coupon cpn : couponList) {
                if (couponUser.getCouponId().equals(cpn.getId()) && couponUser.getUserId().equals(userId)) {
                    couponType = cpn;
                    break;
                }
            }
            //如果couponType为null，说明数据库有严重问题，用户拥有的某一张优惠劵是野优惠劵
            //先跳过这一张优惠劵
            if (couponType == null) {
                continue;
            }
            //有效时间限制
            if (couponType.getTimeType() == 0) {
                //如果是0，则是基于领取时间的有效天数days，即相对时间
                //要先获取用户领取优惠券的时间
                Date createTime = couponUser.getAddTime();
                //判断时间
                //领到优惠劵的那一刻 + 优惠劵有效的天数 * 每一天的毫秒数  <  当前的时间戳说明过期
                if (createTime == null || createTime.getTime() + couponType.getDays() * ONE_DAY_MILLISECOND < System.currentTimeMillis()) {
                    //过期了，将优惠券从可用优惠券id列表中删除
                    //找到couponUser在couponUserList中的下标，在与couponUserList对应的couponIds中删掉这个下标对应的元素，
                    //我们把对应的一项设置为负数即可
                    couponIds.set(couponUserList.indexOf(couponUser), -100);
                    continue;//继续判断下一条优惠券
                }
            }
            // if (cpn.getTimeType() == 1)
            else {
                //如果是1，说明这个优惠劵是根据自己持有的start_time和end_time来判断是否过期的，并不是从用户开始领到算起
                // 则start_time和end_time是优惠券有效期
                Date now = new Date(System.currentTimeMillis());
                if (now.compareTo(couponType.getStartTime()) < 0 || now.compareTo(couponType.getEndTime()) >= 0) {
                    couponIds.set(couponUserList.indexOf(couponUser), -100);//将优惠券从可用优惠券列表中删除
                    continue;//继续判断下一条优惠券
                }
            }
            //商品类型限制
            if (couponType.getGoodsType() == 1) {
                //类目集合限制
                ArrayList<Integer> categorySetLimit = new ArrayList<>();
                //根据goodsId查找categoryid
                for (Cart cart : cartList) {
                    //先拿到商品id的集合
                    Goods goods = goodsMapper.selectByPrimaryKey(cart.getGoodsId());
                    categorySetLimit.add(goods.getCategoryId());
                }
                if (!Arrays.asList(couponType.getGoodsValue()).containsAll(categorySetLimit)) {
                    //当前订单类目超出了优惠券限制类目限制集合
                    couponIds.set(couponUserList.indexOf(couponUser), -100);//将优惠券从可用优惠券列表中删除
                    continue;//继续判断下一条优惠券
                }
            } else if (couponType.getGoodsType() == 2) {
                //商品集合限制
                ArrayList<Integer> goodsSetLimit = new ArrayList<>();
                for (Cart cart : cartList) {
                    goodsSetLimit.add(cart.getGoodsId());
                }
                if (!Arrays.asList(couponType.getGoodsValue()).containsAll(goodsSetLimit)) {
                    //当前订单商品集合超出了限制
                    couponIds.set(couponUserList.indexOf(couponUser), -100);//将优惠券从可用优惠券列表中删除
                    continue;
                }
            }
        }

        List<Coupon> returnCouponList = new ArrayList<>();
        for (Integer id : couponIds) {
            //id < 0的是不合要求的优惠劵，不应该加入list中
            if (id > 0){
                //去map中查找couponId对应的coupon
                Coupon coupon = couponTypeMap.get(id);
                returnCouponList.add(coupon);
            }
        }

        return returnCouponList;
    }

    @Override
    public WXCartIndexVO queryCartIndex(Integer id, Integer cartId, Boolean onlyChecked) {
        CartExample cartExample = new CartExample();
        CartExample.Criteria cartExampleCriteria = cartExample.createCriteria();
        cartExampleCriteria.andUserIdEqualTo(id);

        if (cartId == 0) {//购物车点下单的情况，如果是fastadd不经过购物车页面，不必限定未删除
            cartExampleCriteria.andDeletedEqualTo(false);
        }
        if (cartId > 0) {//fastadd的情形
            cartExampleCriteria.andIdEqualTo(cartId);
        }

        if (onlyChecked) {//只选择已选中的
            cartExampleCriteria.andCheckedEqualTo(onlyChecked);
        }

        List<Cart> cartList = cartMapper.selectByExample(cartExample);
        int goodsCount = 0;
        int checkedGoodsCount = 0;
        BigDecimal goodsAmount = new BigDecimal(0);
        BigDecimal checkedGoodsAmount = new BigDecimal(0);
        for (Cart cart : cartList) {
            //true 表示已选中
            if (cart.getChecked()) {
                checkedGoodsCount += cart.getNumber();
                checkedGoodsAmount = checkedGoodsAmount.add(cart.getPrice());
            }
            goodsCount += cart.getNumber();
            goodsAmount = goodsAmount.add(cart.getPrice());
        }
        WXCartTotalBeanVO totalVo = new WXCartTotalBeanVO(goodsCount, checkedGoodsCount, goodsAmount, checkedGoodsAmount);
        return new WXCartIndexVO(totalVo,cartList);
    }

    /**
     * 这是我们使用的方法
     * @param userId
     * @param bo
     * @param wxCartIndexVO
     * @return
     */
    @Override
    public WXCartCheckOutVO queryCartCheckoutInfo(Integer userId, WXCartCheckOutBO bo, WXCartIndexVO wxCartIndexVO) {
        //groupRulesId不用管
        //先查地址相关信息
        //如果地址id为0，返回默认id，如果不是0，则查找对应地址
        WXCartCheckOutVO checkoutVo = new WXCartCheckOutVO();
        Address userAddress = queryUserAddressByUserId(userId, bo.getAddressId());
        if (userAddress != null) {
            checkoutVo.setCheckedAddress(userAddress);
            checkoutVo.setAddressId(userAddress.getId());
        } else {
            checkoutVo.setCheckedAddress(null);
            checkoutVo.setAddressId(0);
        }

        //购物车商品列表
        List<Cart> cartList = wxCartIndexVO.getCartList();
        checkoutVo.setCheckedGoodsList(cartList);
        //商品总金额
        BigDecimal goodsTotalPrice = wxCartIndexVO.getCartTotal().getCheckedGoodsAmount();

        checkoutVo.setGoodsTotalPrice(goodsTotalPrice);

        //根据总金额是否满88决定运费
        int cmp = goodsTotalPrice.compareTo(new BigDecimal(100));
        if (cmp < 0) {
            checkoutVo.setFreightPrice(8);
        } else {
            checkoutVo.setFreightPrice(0);
        }

        //优惠券相关,根据用户id查询其所有优惠券，如果用户自己选择了优惠券，那优惠券id就不是0了
        // 判断可用优惠券的数量，
        // 挑选优惠金额最大的优惠券，作为默认使用的优惠券

        Coupon coupon = null;
        Integer couponId = bo.getCouponId();

        //List<Coupon> couponList = queryAvailableCouponListOthers(userId, wxCartIndexVO, couponId);//获取可用优惠券订单列表
        List<Coupon> couponList = queryAvailableCouponListTemp(userId, wxCartIndexVO, couponId);
        if (couponId > 0) {
            //用户自己选了优惠券的情况
            //todo
            CouponUser couponUser = couponUserMapper.selectByPrimaryKey(couponId);
            //拿到couponUser的couponId
            Integer couponIdTemp = couponUser.getCouponId();
            //再用couponIdTemp去查找coupon
            coupon = couponMapper.selectByPrimaryKey(couponIdTemp);
//            coupon = couponMapper.selectByPrimaryKey(couponId);  //他的
        } else if (couponId == 0) {
            if (couponList.size() > 0) {
                //可用列表是根据优惠金额从大到小排序的，因此第0个就是优惠值最多的，默认用户会使用这张
                coupon = couponList.get(0);
            }
        }
//        else if (couponId == -1) 不用管 coupon = null

        if (coupon != null && couponList.size() > 0 && couponId != -1) {//选择设置是否显示可用优惠券数量
            checkoutVo.setCouponId(coupon.getId());//有可用优惠券,并且要使用,显示优惠金额
        } else if (coupon == null&&couponList.size() > 0 && couponId == -1) {
            checkoutVo.setCouponId(-1);//有但选择不使用
        } else {
            checkoutVo.setCouponId(0);//没有可用默认显示0
        }

        checkoutVo.setAvailableCouponLength(couponList.size());

        if (coupon != null) {
            checkoutVo.setCouponPrice(coupon.getDiscount());
        }//否则就是没有合适的优惠券，用默认值0；也可能是用户选择不适用优惠券，所以还要设置可用setAvailableCouponLength
        else {
            checkoutVo.setCouponPrice(new BigDecimal(0));
        }

        //团购优惠
        BigDecimal groupDiscount = queryGroupDiscount(userId, bo.getGrouponRulesId(), wxCartIndexVO);
        //加上运费，减去优惠券优惠,减去团购优惠
        BigDecimal orderTotalPrice = goodsTotalPrice.add(new BigDecimal(checkoutVo.getFreightPrice())).subtract(checkoutVo.getCouponPrice()).subtract(groupDiscount);
        checkoutVo.setActualPrice(orderTotalPrice);
        checkoutVo.setOrderTotalPrice(orderTotalPrice);
        int groupDiscountTemp = groupDiscount.intValue();
        checkoutVo.setGrouponPrice(groupDiscountTemp);

        return checkoutVo;
    }

    private Address queryUserAddressByUserId(Integer userId, Integer addressId) {
        AddressExample userAddressExample = new AddressExample();
        AddressExample.Criteria addressExampleCriteria = userAddressExample.createCriteria();
        userAddressExample.setOrderByClause("is_default" + " " + "desc");
        addressExampleCriteria.andUserIdEqualTo(userId)
                .andDeletedEqualTo(false);
//        if (addressId != 0) {
//            addressExampleCriteria.andIdEqualTo(addressId);
//        }

        List<Address> userAddressList = addressMapper.selectByExample(userAddressExample);
        if (userAddressList != null && userAddressList.size() > 0) {
            //如果有明确的addressId
            if (addressId >0){
                return userAddressList.get(0);
            }
            else{
                for (Address address : userAddressList) {
                    //找到默认地址
                    if (address.getIsDefault()){
                        return address;
                    }
                }
            }
//            return userAddressList.get(0);
        }
        return null;
    }

    /**
     * 临时方法
     * @param userId
     * @param cartInfo
     * @param couponId
     * @return
     */
    public List<Coupon> queryAvailableCouponListTemp(Integer userId, WXCartIndexVO cartInfo, Integer couponId) {
        //先根据我们查到的静态购物车信息cartInfo拿到cartList
        List<Cart> cartList = cartInfo.getCartList();
        //存放所有可用的优惠劵
        List<Coupon> couponList = new ArrayList<>();

        CouponUserExample couponUserExample = new CouponUserExample();
        CouponUserExample.Criteria criteria = couponUserExample.createCriteria();
        Date nowTime = new Date(System.currentTimeMillis());
        nowTime = DateTransformUtil.dateFormat(nowTime);
        criteria.andDeletedEqualTo(false)  //拿未被删除的优惠券
                .andStatusEqualTo((short) 0)      //拿状态码为0也就是未被使用过的优惠券
                .andUserIdEqualTo(userId)  //拿当前用户拥有的优惠劵
                .andStartTimeLessThanOrEqualTo(nowTime)   //优惠券开始时间要早于或等于当前时间
                .andAddTimeLessThanOrEqualTo(nowTime);      //优惠券添加的时间要早于或等于当前时间couponUserList
        //按照增加时间由大到小排序
        couponUserExample.setOrderByClause("add_time" + " " + "desc");
        //按照上述条件拿到该用户的所有优惠劵 List<CouponUser>
        List<CouponUser> couponUserList = couponUserMapper.selectByExample(couponUserExample);
        //创建一个ArrayList<Integer> couponIds，用来存放拿到的该用户持有的所有优惠券的优惠劵id
        List<Integer> couponIds = new ArrayList<>();

        //说明该用户没有优惠劵
        //如果List<CouponUser> couponUserList为空，直接返回一个空的ArrayList即可
        if (couponUserList.size() == 0) {
            return new ArrayList<Coupon>();
        }

        //该用户有优惠劵
        for (CouponUser couponUser : couponUserList) {
            couponIds.add(couponUser.getCouponId());
        }

        //拿优惠劵的list
        CouponExample couponExample = new CouponExample();
        //根据优惠金额的力度由大到小排列的
        couponExample.setOrderByClause("discount" + " " + "desc");
        couponExample.createCriteria()
                .andMinLessThanOrEqualTo(cartInfo.getCartTotal().getCheckedGoodsAmount())  //我们这个购物车内选中商品的总金额要大于优惠劵使用的最小额度
                .andIdIn(couponIds)  //要在couponIds范围内，也就是该用户拥有的优惠劵的id
                .andDeletedEqualTo(false)  //未被删除的
                .andStatusEqualTo((short) 0);    //未被使用的
        couponList = couponMapper.selectByExample(couponExample);

        if (couponList.size() == 0){
            //说明没有可以用的，返回空
            return new ArrayList<>();
        }

        //维护一张优惠劵的couponId与优惠劵种类coupon的对应map
        Map<Integer, Coupon> couponTypeMap = new HashMap<>();
        for (Coupon coupon : couponList) {
            if (!couponTypeMap.containsKey(coupon.getId())) {
                couponTypeMap.put(coupon.getId(), coupon);
            }
        }

        List<Coupon> returnCouponList = new ArrayList<>();
        for (Integer id : couponIds) {
            //id < 0的是不合要求的优惠劵，不应该加入list中
            if (id > 0){
                //去map中查找couponId对应的coupon
                Coupon coupon = couponTypeMap.get(id);
                returnCouponList.add(coupon);
            }
        }

        return returnCouponList;
    }

    /**
     * 辅助方法：返回团购折扣
     *
     * @param userId
     * @param groupRulesId
     * @param cartInfo
     * @return
     */
    public BigDecimal queryGroupDiscount(Integer userId, Integer groupRulesId, WXCartIndexVO cartInfo) {

        //团购折扣
        BigDecimal groupDiscount = new BigDecimal(0);
        List<Cart> cartList = cartInfo.getCartList();
        if (groupRulesId > 0) {//团购id<=0表示没有参与团购优惠
            //根据团购规则id查询该团购规则当前是否过期，以及团购规则要求的优惠人数
            GrouponRules grouponRules = grouponRulesMapper.selectByPrimaryKey(groupRulesId);
            if (grouponRules != null
                    && grouponRules.getExpireTime().getTime() < System.currentTimeMillis()//过期校验
                    && cartList.size() == 1  //团购优惠商品校验，要求订单单中有且只有该团购规则中的商品
                    && grouponRules.getGoodsId().equals(cartList.get(0).getGoodsId())) {//团购优惠商品校验，要求订单单中有且只有该团购规则中的商品
                //根据用户id和团购规则id，查找其所在的团购的团id，再查询当前团内有多少人
                GrouponExample grouponExample = new GrouponExample();
                GrouponExample.Criteria criteria = grouponExample.createCriteria();
                criteria.andUserIdEqualTo(userId).andRulesIdEqualTo(groupRulesId).andDeletedEqualTo(false);

                List<Groupon> groupons = grouponMapper.selectByExample(grouponExample);
                if (groupons != null && groupons.size() > 0) {
                    Integer groupId = groupons.get(0).getGrouponId();//拿到团购信息中的团id
                    //根据团id查询团内现有多少人
                    int count = grouponMapper.selectJoinerCountByGrouponId(groupId);
                    if (count >= grouponRules.getDiscountMember()) {
                        groupDiscount = grouponRules.getDiscount();
                    }
                }
            }
        }
        return groupDiscount;
    }


    public List<Coupon> queryAvailableCouponListOthers(Integer userId, WXCartIndexVO cartInfo, Integer couponId) {
        List<Cart> cartList = cartInfo.getCartList();
        List<Coupon> couponList = new ArrayList<>();

        CouponUserExample couponUserExample = new CouponUserExample();
        CouponUserExample.Criteria criteria = couponUserExample.createCriteria();
        Date nowTime = new Date(System.currentTimeMillis());
        criteria.andDeletedEqualTo(false)
                .andStatusEqualTo((short) 0)
                .andUserIdEqualTo(userId)
                .andStartTimeLessThanOrEqualTo(nowTime)
                .andEndTimeGreaterThan(nowTime);
        couponUserExample.setOrderByClause("add_time" + " " + "desc");
        List<CouponUser> couponUserList = couponUserMapper.selectByExample(couponUserExample);
        ArrayList<Integer> couponIds = new ArrayList<>();
        for (CouponUser couponUser : couponUserList) {
            couponIds.add(couponUser.getCouponId());
        }
//        for (int i = couponUserList.size() - 1; i >= 0; i--) {
////            if (couponUserList.get(i).getStartTime().getTime() > nowTime.getTime() || couponUserList.get(i).getEndTime().getTime() < nowTime.getTime()) {
////                couponUserList.remove(couponUserList.get(i));
////                continue;
////            }
//            couponIds.add(couponUserList.get(i).getCouponId());
//        }

        CouponExample couponExample = new CouponExample();
        couponExample.setOrderByClause("discount" + " " + "desc");
        CouponExample.Criteria couponExampleCriteria = couponExample.createCriteria();
        couponExampleCriteria
                .andMinLessThanOrEqualTo(cartInfo.getCartTotal().getCheckedGoodsAmount())
                .andDeletedEqualTo(false)
                .andStatusEqualTo((short) 0);
        if (couponIds.size() > 0) {
            couponExampleCriteria.andIdIn(couponIds);

            couponList = couponMapper.selectByExample(couponExample);
        } else {
            return couponList;
        }
        //到此还有goods_type和time_type限制没有检测
        ArrayList<Integer> unavailableIds = new ArrayList<>();
        ArrayList<Integer> unavailableIds2 = new ArrayList<>();
        for (Coupon cpn : couponList) {
//            //有效时间限制
//            if (cpn.getTimeType() == 0) {
//                //如果是0，则基于领取时间的有效天数days
//                //要先获取用户领取优惠券的时间
//                Date createTime = null;
//                for (CouponUser couponUser : couponUserList) {
//                    if (couponUser.getCouponId() == cpn.getId() && couponUser.getUserId() == userId) {
//                        //找到了该用户领的的这张优惠券
//                        createTime = couponUser.getAddTime();
//                        //考虑到用户的这种优惠券可能不止一张，将这张排除以免影响下次循环
//                        unavailableIds.add(couponUserList.indexOf(couponUser));
//                        break;
//                    }
//                }
//                for (Integer unavailableId : unavailableIds) {
//                    couponUserList.remove(unavailableId);
//                }
//
//                if (createTime == null || createTime.getTime() + cpn.getDays() * ONE_DAY_MILLISECOND < System.currentTimeMillis()) {
//                    //过期了
//                    unavailableIds2.add(couponList.indexOf(cpn));//将优惠券从可用优惠券列表中删除
//                    continue;//继续判断下一条优惠券
//                }
//            } else {
//                //如果是1，则start_time和end_time是优惠券有效期
//                Date now = new Date(System.currentTimeMillis());
//                if (now.compareTo(cpn.getStartTime()) < 0 || now.compareTo(cpn.getEndTime()) >= 0) {
//                    unavailableIds2.add(couponList.indexOf(cpn));//将优惠券从可用优惠券列表中删除
//                    continue;//继续判断下一条优惠券
//                }
//            }
            //商品类型限制
            if (cpn.getGoodsType() == 1) {
                //类目集合限制
                ArrayList<Integer> categorySetLimit = new ArrayList<>();
                //根据goodsId查找categoryid
                for (Cart cart : cartList) {
                    Goods goods = goodsMapper.selectByPrimaryKey(cart.getGoodsId());
                    categorySetLimit.add(goods.getCategoryId());
                }
                if (!Arrays.asList(cpn.getGoodsValue()).containsAll(categorySetLimit)) {
                    //当前订单类目超出了优惠券限制类目限制集合
                    unavailableIds2.add(couponList.indexOf(cpn));//将优惠券从可用优惠券列表中删除
                    continue;//继续判断下一条优惠券
                }
            } else if (cpn.getGoodsType() == 2) {
                //商品集合限制
                ArrayList<Integer> goodsSetLimit = new ArrayList<>();
                for (Cart cart : cartList) {
                    goodsSetLimit.add(cart.getGoodsId());
                }
                if (!Arrays.asList(cpn.getGoodsValue()).containsAll(goodsSetLimit)) {
                    //当前订单商品集合超出了限制
                    unavailableIds2.add(couponList.indexOf(cpn));
                    continue;
                }
            }
        }
        for (Integer integer : unavailableIds2) {//删除不和要求的
            couponList.remove(integer);
        }
        return couponList;
    }


}
